#include "test.h"


_FILE * _fopen(const char * path_name, const char* mode)
{
    int fd = -1;
    int flag =0;
    if(strcmp(mode ,"r")==0)
    {
        flag |= O_RDONLY;
    }
    else if(strcmp(mode, "w")==0)
    {
        flag |= (O_WRONLY | O_CREAT | O_TRUNC);
    }
    else if(strcmp(mode, "a")==0)
    {
        flag |= (O_WRONLY | O_APPEND | O_CREAT);
    }
    else{
        //NULL;
    }
    if(flag & O_CREAT) fd = open(path_name, flag, 0666);
    else fd = open(path_name, flag);

    if(fd <0){ 
        //文件打开失败
        write(2,strerror(errno),strlen(strerror(errno)));
        return NULL;
        //这就是为什么文件打开失败会返回NULL
    }
    _FILE* fp = (_FILE*)malloc(sizeof(_FILE));
    assert(fp != NULL);
    fp->fileno = fd;
    fp->flags= LINE;
    //打开不同的文件这个flag需要填入不同的数据
    //需要我们判断一下，但是今天我们就不写那么复杂了
    //演示行刷新就行。
    
    fp->size =0 ;
    fp->cap = SIZE;
    memset(fp->buf, 0 ,SIZE);//给buf初始化为0
    return fp;
}


void _fflush(_FILE * fp)
{
    //fflush就是把缓冲区的文件刷新到磁盘文件。
    //并且清空缓冲区
    if(fp->size > 0) 
    {
        write(fp->fileno, fp->buf, fp->size);
        fsync(fp->fileno);
        fp->size = 0;
    }
}

void _fclose(_FILE* fp)
{
    //语言层面的关闭文件就是刷新缓冲区，然后关闭文件
    _fflush(fp);
    close(fp->fileno);
}

void _fwrite(const char* ptr,size_t num, _FILE* fp)
{
    //C语言库函数写入的本质是：将数据拷贝到FILE结构中的缓冲区buf中
    //然后更具不同的刷新规则检查释放需要将，缓冲区刷出到磁盘文件。
    memcpy(fp->buf + fp->size,ptr, num);
    fp->size += num;
    //这里简化不考虑缓冲区溢出的问题。
    //如果想考虑就需要判断大小，其实也不难
    //今天是为了演示原理。
    

    //根据不同的刷新方式检查是否刷新
    if(fp->flags & NOW)
    {
        _fflush(fp);
    }
    else if(fp->flags & LINE)
    {
        if(fp->buf[fp->size - 1] == '\n')
        {
            _fflush(fp);
       }
        //这里并不完善，例如：assd\nasda 这种情况就会出问题
        //但是今天不考虑
    }
    else if(fp->flags & FULL)
    {
        if(fp->size == fp->cap)
        {
           _fflush(fp);
        }
    }
    else{
        //error
    }

}





